package com.sec.android.app.myfiles.fragment.optimizestorage;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.text.format.Formatter;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.feature.CloudMgr;
import com.sec.android.app.myfiles.feature.MultiWindowMgr;
import com.sec.android.app.myfiles.fragment.AbsMyFilesFragment;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.listener.ListenerMgr;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.log.SamsungAnalyticsLog;
import com.sec.android.app.myfiles.module.ModuleLoader;
import com.sec.android.app.myfiles.module.abstraction.AbsContentObserverImp;
import com.sec.android.app.myfiles.module.abstraction.AbsReloadStrategyImp;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageAdapterImp;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageDbTableInfo;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageFileRecord;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationManager;
import com.sec.android.app.myfiles.provider.DbTableInfo;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.UiUtils;

import java.util.ArrayList;

import static com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaScanFinish;
import static com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaUnmounted;

/**
 * Created by daesu83.kim on 2016-10-12.
 */

public class OptimizeStorageOverviewFragment extends AbsMyFilesFragment
        implements View.OnClickListener, android.app.LoaderManager.LoaderCallbacks<Cursor> {

    private static final int ID_GET_POTENTIAL_SPACE_SIZE = 10;

    protected ListenerMgr mListenerMgr;

    protected AbsReloadStrategyImp mReloadStrategy;

    private SparseArray<CardContents> mCardContents = new SparseArray<>();

    private View mPotentialSpaceSizeContainer;
    private TextView mPotentialSpaceSizeTextView;
    private TextView mPotentialSpaceSizeUnitTextView;
    private View mPotentialSpaceGraph;
    private View mPotentialSpaceGraphPotentialSpaceBar;
    private View mPotentialSpaceGraphUsedBar;
    private View mPotentialSpaceGraphFreeBar;
    private TextView mUsageTitleTextView;
    private TextView mUsedSizeInGraphTextView;
    private TextView mTotalSizeInGraphTextView;
    private TextView mRecommendedSizeInGraphTextView;
    private TextView mPotentialSpaceGraphDescriptionTextView;
    private boolean[] mIsLoadFinished;
    private CloudMgr mCloudMgr;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        OptimizeStorageFileRecord.mOverviewWorking = true;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        OptimizeStorageFileRecord.mOverviewWorking = false;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCloudMgr = CloudMgr.getInstance(mContext);
        mCloudMgr.addSignInStateChangeListener(mSignInStateChangeListener);
        mListenerMgr = new ListenerMgr();
        mListenerMgr.addListener(new SystemBroadcastReceiver(mContext, mMediaUnmountedListener, ListenerMgr.LifeCycle.CREATE, ListenerMgr.LifeCycle.DESTROY));
        mListenerMgr.addListener(new SystemBroadcastReceiver(mContext, mMediaScanFinishedListener, ListenerMgr.LifeCycle.CREATE, ListenerMgr.LifeCycle.DESTROY));
        mListenerMgr.notifyCreate();
        mReloadStrategy = ModuleLoader.getInstance().createReloadStrategy(mContext, getNavigationInfo());
        PreferenceUtils.setGmsVisitFlag(mContext);
        registerTimeChangedReceiver();
    }

    private void registerTimeChangedReceiver() {
        try {
            getContext().registerReceiver(mTimeChangedReceiver, new IntentFilter(Intent.ACTION_TIME_CHANGED));
        } catch (NullPointerException e) {
            Log.e(this, "Fail to register TimeChangedReceiver : " + e.toString());
        }
    }

    private void unregisterTimeChangedReceiver() {
        try {
            getContext().unregisterReceiver(mTimeChangedReceiver);
        } catch (IllegalArgumentException e) {
            Log.e(this, "Fail to unregister TimeChangedReceiver : " + e.toString());
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        int layoutResId = R.layout.optimize_storage_overview_layout;
        if (MultiWindowMgr.getInstance(mActivity,mProcessId).getWindowState() == MultiWindowMgr.WindowState.LANDSCAPE &&
                !AppFeatures.isTabletUIMode()) {
            layoutResId = R.layout.optimize_storage_overview_layout_land;
        }
        return inflater.inflate(layoutResId, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initLayout(view);
        startOptimizeStorage();
        setActionMode(ActionModeType.NORMAL);
        mActivity.invalidateOptionsMenu();
//        SamsungAnalyticsLog.setScreenInfo(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE);  // TODO : HJ SA
    }

    @Override
    public void setPathIndicatorDivider(ImageView pathIndicatorDivider) {
        if (pathIndicatorDivider != null) {
            pathIndicatorDivider.setVisibility(View.GONE);
        }
    }

    private void initLayout(View root) {
        mPotentialSpaceSizeContainer = root.findViewById(R.id.potential_space_size_container);
        mPotentialSpaceSizeTextView = (TextView) root.findViewById(R.id.potential_space_size);
        mPotentialSpaceSizeUnitTextView = (TextView) root.findViewById(R.id.potential_space_size_unit);
        mPotentialSpaceGraph = root.findViewById(R.id.potential_space_graph);
        mPotentialSpaceGraphPotentialSpaceBar = root.findViewById(R.id.potential_space_graph_potential_space_bar);
        mPotentialSpaceGraphUsedBar = root.findViewById(R.id.potential_space_graph_used_bar);
        mPotentialSpaceGraphFreeBar = root.findViewById(R.id.potential_space_graph_free_bar);
        mUsageTitleTextView = (TextView) root.findViewById(R.id.graph_usage_title);
        mUsedSizeInGraphTextView = (TextView) root.findViewById(R.id.usage_graph_used_text);
        mTotalSizeInGraphTextView = (TextView) root.findViewById(R.id.usage_graph_total_text);
        mRecommendedSizeInGraphTextView = (TextView) root.findViewById(R.id.recommended_for_clean_up_text);
        mPotentialSpaceGraphDescriptionTextView = (TextView) root.findViewById(R.id.info_panel_text);

        setLimitationLargeText();
        updateUsageInfo();
        updatePotentialSpaceSize(0L);

        initCardView(root, R.id.card_large_files, R.string.large_files,
                getString(R.string.large_files_description, Formatter.formatShortFileSize(mContext, PreferenceUtils.getLargeFilesSize(mContext))));

        int unusedFilesPeriod = PreferenceUtils.getUnusedFilesPeriod(mContext);
        String desc = getResources().getQuantityString(R.plurals.unused_files_description, unusedFilesPeriod, unusedFilesPeriod);
        initCardView(root, R.id.card_unused_files, R.string.unused_files, desc);

        initCardView(root, R.id.card_duplicate_files, R.string.duplicate_files, R.string.duplicate_files_description);
        initCardView(root, R.id.card_unnecessary_data, R.string.unnecessary_data, R.string.unnecessary_data_description);

        mIsLoadFinished = new boolean[mCardContents.size()];
    }

    private void setLimitationLargeText() {
        UiUtils.limitLargeTextSize(mContext, mPotentialSpaceSizeTextView);
        UiUtils.limitLargeTextSize(mContext, mPotentialSpaceSizeUnitTextView);
        UiUtils.limitLargeTextSize(mContext, mUsageTitleTextView);
        UiUtils.limitLargeTextSize(mContext, mUsedSizeInGraphTextView);
        UiUtils.limitLargeTextSize(mContext, mTotalSizeInGraphTextView);
        UiUtils.limitLargeTextSize(mContext, mRecommendedSizeInGraphTextView);
        UiUtils.limitLargeTextSize(mContext, mPotentialSpaceGraphDescriptionTextView);
    }

    private void updateUsageInfo() {
        long totalSize = StorageMonitor.getInternalTotalSize(mContext);
        long freeSpace = StorageMonitor.getStorageFreeSpace(mContext, StorageMonitor.iStorageType.INTERNAL);
        long usedSize = totalSize - freeSpace;

        if (totalSize != 0) {
            float usedRatio = (float) usedSize / totalSize;
            ((LinearLayout.LayoutParams) mPotentialSpaceGraphUsedBar.getLayoutParams()).weight = (1.0f - usedRatio);
            ((LinearLayout.LayoutParams) mPotentialSpaceGraphFreeBar.getLayoutParams()).weight = usedRatio;
        }
        mTotalSizeInGraphTextView.setText(getString(R.string.optimize_storage_total_size, Formatter.formatShortFileSize(mContext, totalSize)));
        mUsedSizeInGraphTextView.setText(getString(R.string.optimize_storage_used_size, Formatter.formatFileSize(mContext, (totalSize - freeSpace))));
    }

    private void updatePotentialSpaceSize(long size) {
        String strSize = setSizeWithUnit(size, mPotentialSpaceSizeTextView, mPotentialSpaceSizeUnitTextView);
        mRecommendedSizeInGraphTextView.setText(getString(R.string.optimize_storage_recommended_size, Formatter.formatFileSize(mContext, size)));
        updatePotentialSpaceGraph(size);
        mPotentialSpaceSizeContainer.setContentDescription(strSize);
    }

    private void updatePotentialSpaceGraph(long potentialSpaceSize) {
        long totalSize = StorageMonitor.getInternalTotalSize(mContext);

        if (totalSize != 0) {
            if (potentialSpaceSize <= 0L) {
                mPotentialSpaceGraphPotentialSpaceBar.setVisibility(View.GONE);
            } else {
                mPotentialSpaceGraphPotentialSpaceBar.setVisibility(View.VISIBLE);
                int minWidth = (int) (getResources().getDimension(R.dimen.optimize_storage_overview_usage_graph_bar_stroke_width) * 2);
                float potentialSpaceRatio = (float) potentialSpaceSize / totalSize;
                int width = (int) (mPotentialSpaceGraph.getWidth() * potentialSpaceRatio);
                if (width < minWidth) {
                    width = minWidth;
                }
                mPotentialSpaceGraphPotentialSpaceBar.getLayoutParams().width = width;
                mPotentialSpaceGraphPotentialSpaceBar.requestLayout();
            }
        }
    }

    private String setSizeWithUnit(long size, TextView sizeTextView, TextView sizeUnitTextView) {
        String ret = "";
        SizeInfo sizeInfo = SizeInfo.getSizeInfo(mContext, size);
        if (sizeTextView != null && sizeUnitTextView != null) {
            sizeTextView.setText(sizeInfo.mFormattedValue);
            sizeUnitTextView.setText(sizeInfo.mSizeUnit);
            ret = sizeInfo.mFormattedValue + ' ' + sizeInfo.mSizeUnit;
        }
        return ret;
    }

    private void initCardView(View root, int viewId, int titleResId, int textResId) {
        initCardView(root, viewId, titleResId, getString(textResId));
    }

    private void initCardView(View root, int viewId, int titleResId, String descText) {
        View cardView = root.findViewById(viewId);
        if (cardView != null) {
            if (viewId == R.id.card_large_files) {
                cardView.requestFocus();
            }
            CardContents contents = new CardContents();
            contents.mCardView = cardView;
            contents.mCardView.setOnClickListener(this);
            contents.mTitle = (TextView) cardView.findViewById(R.id.card_title);
            contents.mDescription = (TextView) cardView.findViewById(R.id.card_text);
            contents.mSize = (TextView) cardView.findViewById(R.id.size);
            contents.mSizeUnit = (TextView) cardView.findViewById(R.id.size_unit);
            contents.mItemCount = (TextView) cardView.findViewById(R.id.item_count);
            contents.mDetailListIcon = cardView.findViewById(R.id.detail_icon);
            contents.mProgress = cardView.findViewById(R.id.progress);

            if (contents.mTitle != null) {
                contents.mTitle.setText(titleResId);
                UiUtils.limitLargeTextSize(mContext, contents.mTitle);
            }
            if (contents.mDescription != null) {
                contents.mDescription.setText(descText);
                UiUtils.limitLargeTextSize(mContext, contents.mDescription);
            }

            NavigationInfo info = NavigationInfo.getInstance(NavigationInfo.NavigationMode.Normal,
                    getOptimizeStorageFileRecord(viewId));
            contents.mAdapter = new OptimizeStorageAdapterImp(getActivity(), info, 0, null, 0);
            mCardContents.put(viewId, contents);
        }
    }

    private FileRecord getOptimizeStorageFileRecord(int viewId) {
        return new OptimizeStorageFileRecord(OptimizeStorageFileRecord.getOptimizeStoragePath(
                getOptimizeStorageType(viewId)));
    }

    private void startOptimizeStorage() {
        int size = mCardContents.size();
        for (int i = 0; i < size; i++) {
            int cardId = mCardContents.keyAt(i);
            getLoaderManager().initLoader(cardId, null, this);
            CardContents cardContents = mCardContents.get(cardId);
            if (cardContents != null) {
                cardContents.showProgress(true);
            }
        }
    }

    private void restartOptimizeStorage() {
        restartOptimizeStorage(FileRecord.OptimizeStorageType.LargeFiles);
        restartOptimizeStorage(FileRecord.OptimizeStorageType.UnusedFiles);
        restartOptimizeStorage(FileRecord.OptimizeStorageType.DuplicateFiles);
        restartOptimizeStorage(FileRecord.OptimizeStorageType.UnnecessaryData);
    }

    private void restartOptimizeStorage(FileRecord.OptimizeStorageType optimizeStorageType) {
        int cardId = -1;
        switch (optimizeStorageType) {
            case LargeFiles:
                cardId = R.id.card_large_files;
                break;
            case UnusedFiles:
                cardId = R.id.card_unused_files;
                break;
            case DuplicateFiles:
                cardId = R.id.card_duplicate_files;
                break;
            case UnnecessaryData:
                cardId = R.id.card_unnecessary_data;
                break;
        }
        if (cardId != -1) {
            CardContents cardContents = mCardContents.get(cardId);
            if (cardContents != null) {
                cardContents.showProgress(true);
                cardContents.mAdapter.needRefresh();
            }
            getLoaderManager().restartLoader(cardId, null, this);
        }
    }

    private void updateCardSizeInfo(CardContents cardContents,
                                    FileRecord.OptimizeStorageType type, Cursor cursor, long size) {
        if (cursor != null) {
            switch (type) {
                case DuplicateFiles:
                case UnnecessaryData:
                    int count = cursor.getCount();
                    cardContents.mItemCount.setVisibility(View.VISIBLE);
                    cardContents.mItemCount.setText(UiUtils.makeItemsString(mContext, count));
                    break;
            }
        }
        setSizeWithUnit(size, cardContents.mSize, cardContents.mSizeUnit);
    }

    private FileRecord.OptimizeStorageType getOptimizeStorageType(int cardId) {
        FileRecord.OptimizeStorageType ret = FileRecord.OptimizeStorageType.None;
        switch (cardId) {
            case R.id.card_large_files:
                ret = FileRecord.OptimizeStorageType.LargeFiles;
                break;

            case R.id.card_unused_files:
                ret = FileRecord.OptimizeStorageType.UnusedFiles;
                break;

            case R.id.card_duplicate_files:
                ret = FileRecord.OptimizeStorageType.DuplicateFiles;
                break;

            case R.id.card_unnecessary_data:
                ret = FileRecord.OptimizeStorageType.UnnecessaryData;
                break;
        }
        return ret;
    }

    @Override
    public void onClick(View v) {
        final int cardId = v.getId();
        FileRecord record;
        FileRecord.OptimizeStorageType type = getOptimizeStorageType(cardId);
        if (type != FileRecord.OptimizeStorageType.None) {
            record = new OptimizeStorageFileRecord(OptimizeStorageFileRecord.getOptimizeStoragePath(type));
            NavigationInfo info = NavigationInfo.getInstance(NavigationInfo.NavigationMode.Optimize_storage_files, record);
            sendSALog(type, info);
            NavigationManager.getInstance(getProcessId()).enter(info);
        }
    }

    private void sendSALog(FileRecord.OptimizeStorageType type, NavigationInfo info) {
        SamsungAnalyticsLog.Event event = null;
        switch (type) {
            case LargeFiles:
                event = SamsungAnalyticsLog.Event.LARGE_FILES;
                info.setScreenPath(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_LARGE);
                break;
            case UnusedFiles:
                event = SamsungAnalyticsLog.Event.UNUSED_FILES;
                info.setScreenPath(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_UNUSED);
                break;
            case DuplicateFiles:
                event = SamsungAnalyticsLog.Event.DUPLICATE_FILES;
                info.setScreenPath(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_DUPLICATE);
                break;
            case UnnecessaryData:
                event = SamsungAnalyticsLog.Event.UNNECESSARY_FILES;
                info.setScreenPath(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_UNNECESSARY);
                break;
        }
        if (event != null) {
            SamsungAnalyticsLog.sendLog(getProcessId(), event, null);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        CursorLoader ret = null;
        if (id == ID_GET_POTENTIAL_SPACE_SIZE) {
            ret = getPotentialSpaceSizeLoader();
        } else {
            CardContents card = mCardContents.get(id);
            if (card == null) {
                Log.e(this, "onCreateLoader() ] card(" + id + ") is null");
            } else {
                OptimizeStorageAdapterImp adapter = card.mAdapter;
                Uri uri = adapter.getUri();
                Log.d(this, "onCreateLoader() ] adapter.getUri() = " + uri);
                ret = new CursorLoader(mContext, uri, adapter.getProjection(), adapter.getSelection(),
                        adapter.getSelectionArgs(), adapter.getOrderBy());
            }
        }
        return ret;
    }

    private CursorLoader getPotentialSpaceSizeLoader() {
        DbTableInfo tableInfo = OptimizeStorageDbTableInfo.getInstance();
        Uri uri = Uri.parse(tableInfo.getUri()).buildUpon()
                .appendQueryParameter(OptimizeStorageDbTableInfo.QUERY_PARAM_OPTIMIZE_STORAGE_TYPE,
                        FileRecord.OptimizeStorageType.PotentialSpaceSize.toString()).build();
        return new CursorLoader(mContext, uri, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        final int id = loader.getId();
        if (id != -1) {
            boolean isEmptyResult = (data == null || data.getCount() == 0);
            if (id == ID_GET_POTENTIAL_SPACE_SIZE) {
                if (!isEmptyResult && data.moveToFirst()) {
                    mPotentialSpaceGraphHandler.removeMessages(0);
                    mPotentialSpaceGraphHandler.sendMessageDelayed(mPotentialSpaceGraphHandler
                            .obtainMessage(0, data.getLong(0)), 100);
                }
            } else {
                CardContents cardContents = mCardContents.get(id);
                if (cardContents != null) {
                    FileRecord.OptimizeStorageType type = getOptimizeStorageType(id);
                    long totalSize = getTotalSize(data);
                    cardContents.setEnabled(!isEmptyResult);
                    cardContents.showDetailListIcon(!isEmptyResult);
                    updateCardSizeInfo(cardContents, type, data, totalSize);
                    cardContents.showProgress(false);
                    if (!isEmptyResult) {
                        getLoaderManager().restartLoader(ID_GET_POTENTIAL_SPACE_SIZE, null, this);
                    }
                }
                mIsLoadFinished[getOptimizeStorageIndex(id)] = true;
                sendResponseForBixby();
            }
        }
    }

    private int getOptimizeStorageIndex(int id) {
        int index = 0;
        switch (id) {
            case R.id.card_unused_files:
                index = 1;
                break;
            case R.id.card_duplicate_files:
                index = 2;
                break;
            case R.id.card_unnecessary_data:
                index = 3;
                break;
        }
        return index;
    }

    private void sendResponseForBixby() {
        int count = 0;
        for (int i = 0; i < mCardContents.size(); i++) {
            if (mIsLoadFinished[i]) {
                count++;
            }
        }
        if (count == mCardContents.size()) {
        }
    }

    private long getTotalSize(Cursor data) {
        long ret = 0L;
        if (data != null) {
            Bundle extras = data.getExtras();
            if (extras != null) {
                ret = extras.getLong(OptimizeStorageDbTableInfo.EXTRAS_KEY_TOTAL_SIZE, 0L);
            }
        }
        return ret;
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {

    }

    @Override
    protected void _onContentChanged(int event) {
        if (mReloadStrategy != null) {
            mReloadStrategy.reload(AbsReloadStrategyImp.ReloadCause.ContentChanged, null, event);
        }
    }

    private static class CardContents {
        View mCardView;
        TextView mTitle;
        TextView mDescription;
        TextView mSize;
        TextView mSizeUnit;
        TextView mItemCount;
        View mDetailListIcon;
        View mProgress;
        OptimizeStorageAdapterImp mAdapter;

        public void showDetailListIcon(boolean show) {
            if (mDetailListIcon != null) {
                mDetailListIcon.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
            }
            mCardView.setClickable(show);
        }

        public void showProgress(boolean show) {
            if (show) {
                setEnabled(true);
                showDetailListIcon(false);
                mSize.setText("");
                mSizeUnit.setText("");
                mItemCount.setText("");
            }
            if (mProgress != null) {
                mProgress.setVisibility(show ? View.VISIBLE : View.GONE);
            }
        }

        public void setEnabled(boolean enabled) {
            if (mCardView != null) {
                if (mCardView.isEnabled() != enabled) {
                    mCardView.setEnabled(enabled);
                    View container = mCardView.findViewById(R.id.card_container);
                    if (enabled) {
                        container.setAlpha(1.0f);
                    } else {
                        container.setAlpha(0.4f);
                    }
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mCloudMgr.removeSignInStateChangeListener(mSignInStateChangeListener);
        mListenerMgr.notifyDestroy();
        unregisterTimeChangedReceiver();
        destroyObserver();
        int size = mCardContents.size();
        for (int i = 0; i < size; i++) {
            int cardId = mCardContents.keyAt(i);
            getLoaderManager().destroyLoader(cardId);
        }
        mCardContents.clear();
    }

    private void destroyObserver() {
        Log.d(this, "destroyObserver");
        if (mNavigationInfo != null) {
            for (int i = 0; i < mNavigationInfo.getObserverSize(); i++) {
                AbsContentObserverImp observerImp = mNavigationInfo.getContentObserver(i);
                if (observerImp != null) {
                    observerImp.destroy();
                }
            }
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        UiUtils.replaceFragment(this);
    }

    @Override
    public void reload() {
    }

    @Override
    public ArrayList<FileRecord> getSelectedFile() {
        return null;
    }

    @Override
    public int getSelectedFileCount() {
        return 0;
    }

    @Override
    public int getTotalFileCount() {
        return 0;
    }

    @Override
    public int getTotalCheckableFileCount() {
        return 0;
    }

    @Override
    public FileRecord getFileRecord(int position) {
        return null;
    }

    @Override
    public void selectAll(boolean select) {
    }

    @Override
    public void setEmptyView() {
    }

    @Override
    public void clearEmptyView() {
    }

    @Override
    public void onLoadFinished() {
    }

    @Override
    public void setLoadingView() {
    }

    @Override
    public AbsListView getListView() {
        return null;
    }


    private Handler mPotentialSpaceGraphHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Long size = (Long) msg.obj;
            if (isAdded()) {
                updatePotentialSpaceSize(size);
            }
            return true;
        }
    });

    private BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
                Log.d(this, "mTimeChangedReceiver : Time is changed.");
                restartOptimizeStorage(FileRecord.OptimizeStorageType.UnusedFiles);
            }
        }
    };

    private OnMediaUnmounted mMediaUnmountedListener = new OnMediaUnmounted() {
        @Override
        public void onMediaUnmounted(String path) {
            Log.d(this, "onMediaUnmounted");
            if (StorageMonitor.isRemovedExtSDCard(path)) {
                restartOptimizeStorage();
            }
        }
    };

    private OnMediaScanFinish mMediaScanFinishedListener = new OnMediaScanFinish() {
        @Override
        public void onMediaScanFinish() {
            Log.d(this, "onMediaScanFinished");
            restartOptimizeStorage();
        }
    };

    private CloudMgr.OnSignInStateChangeListener mSignInStateChangeListener = new CloudMgr.OnSignInStateChangeListener() {
        @Override
        public void onSignInStateChanged(FileRecord.CloudType cloudType, boolean signedIn) {
            Log.d(this, "onSignInStateChanged:" + cloudType + ", " + signedIn);
            restartOptimizeStorage(FileRecord.OptimizeStorageType.DuplicateFiles);
        }
    };


    private static class SizeInfo {
        private static final int FLAG_SHORTER = 1 << 0;
        private static final int FLAG_CALCULATE_ROUNDED = 1 << 1;

        public float mValue;
        public String mFormattedValue;
        public String mSizeUnit;
        public long mRoundedBytes;

        public SizeInfo(float value, String formatttedValue, String units, long roundedBytes) {
            mValue = value;
            mFormattedValue = formatttedValue;
            mSizeUnit = units;
            mRoundedBytes = roundedBytes;
        }

        public static SizeInfo getSizeInfo(Context context, long sizeBytes) {
            return getSizeInfo(context, sizeBytes, 0);
        }

        public static SizeInfo getShortSizeInfo(Context context, long sizeBytes) {
            return getSizeInfo(context, sizeBytes, 1);
        }

        // the logic of this method same as Formatter.formatBytes() method.
        private static SizeInfo getSizeInfo(Context context, long sizeBytes, int flags) {
            if (context != null) {
                final boolean isNegative = (sizeBytes < 0);
                float result = isNegative ? -sizeBytes : sizeBytes;
                int suffix = R.string.byteShort;
                long mult = 1;
                if (result > 900) {
                    suffix = R.string.kilobyteShort;
                    mult = FileUtils.KILO_BYTES;
                    result = result / 1024;
                }
                if (result > 900) {
                    suffix = R.string.megabyteShort;
                    mult = FileUtils.MEGA_BYTES;
                    result = result / 1024;
                }
                if (result > 900) {
                    suffix = R.string.gigabyteShort;
                    mult = FileUtils.GIGA_BYTES;
                    result = result / 1024;
                }
                if (result > 900) {
                    suffix = R.string.terabyteShort;
                    mult = FileUtils.TERA_BYTES;
                    result = result / 1024;
                }
                if (result > 900) {
                    suffix = R.string.petabyteShort;
                    mult = FileUtils.PETA_BYTES;
                    result = result / 1024;
                }
                // Note we calculate the rounded long by ourselves, but still let String.format()
                // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
                // floating point errors.
                final int roundFactor;
                final String roundFormat;
                if (mult == 1 || result >= 100) {
                    roundFactor = 1;
                    roundFormat = "%.0f";
                } else if (result < 1) {
                    roundFactor = 100;
                    roundFormat = "%.2f";
                } else if (result < 10) {
                    if ((flags & FLAG_SHORTER) != 0) {
                        roundFactor = 10;
                        roundFormat = "%.1f";
                    } else {
                        roundFactor = 100;
                        roundFormat = "%.2f";
                    }
                } else { // 10 <= result < 100
                    if ((flags & FLAG_SHORTER) != 0) {
                        roundFactor = 1;
                        roundFormat = "%.0f";
                    } else {
                        roundFactor = 100;
                        roundFormat = "%.2f";
                    }
                }

                if (isNegative) {
                    result = -result;
                }
                final String roundedString = String.format(roundFormat, result);

                // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
                // it's okay (for now)...
                final long roundedBytes =
                        (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
                                : (((long) Math.round(result * roundFactor)) * mult / roundFactor);

                final String units = context.getString(suffix);

                return new SizeInfo(result, roundedString, units, roundedBytes);
            } else {
                return new SizeInfo(0f, "", "", 0);
            }
        }
    }
}
